<?php
/**
 * Created by PhpStorm.
 * User: 小灰灰
 * Date: 2023-02-22
 * Time: 9:41:08
 * Info: 后台登录
 */

namespace app\admin\controller;

use app\common\controller\AdminController;
use think\facade\Db;
use think\facade\Cache;
use think\facade\View;
use think\captcha\facade\Captcha;
use app\common\model\Admin as AdminModel;
use app\common\model\LoginLog as LoginLogModel;

class Login extends Base
{

    /**
     * 初始化函数
     * @return void
     */
    public function initialize()
    {
        parent::initialize();
        //获取当前的操作名
        $action = $this->request->action();
        //查看session是否有admin或者是否是退出操作
        if ( ! empty(session('admin')) && ! in_array($action, ['logout'])) {
            $this->success(__('AlreadyLoggedIn,NoNeedToLoginAgain'), [], "", url('admin/index/index'));
        }
    }

    /**
     * 后台登录
     * @return \think\response\View
     */
    public function index()
    {
        $login_captcha = get_config('login_captcha');
        View::assign('login_captcha', $login_captcha);

        return View::fetch();
    }

    /**
     * 校验登录
     * @return void
     * @throws \think\db\exception\DataNotFoundException    数据没找到异常错误
     * @throws \think\db\exception\DbException              数据库连接异常错误
     * @throws \think\db\exception\ModelNotFoundException   model模型没找到异常错误
     */
    public function checkLogin()
    {
        //获取参数
        $param         = $this->request->param();
        $login_captcha = get_config('login_captcha');
        //验证验证码
        if ($login_captcha == 1) {
            //验证码必填
            if (empty($param['captcha'])) {
                $this->error(__('%s CantBeEmpty', [__('Captcha')]));
            }
            if ( ! captcha_check($param['captcha'])) {
                $this->error(__('%s Incorrect', [__('Captcha')]));
            }
        }
        //验证用户名
        if (empty($param['username'])) {
            $this->error(__('%s CantBeEmpty', [__('Username')]));
        }
        //验证密码
        if (empty($param['password'])) {
            $this->error(__('%s CantBeEmpty', [__('Password')]));
        }
        //获取admin表的查询数据
        $adminInfo = AdminModel::where('username', $param['username'])->find();
        if (empty($adminInfo)) {
            //获取用户失败，拼接日志data
            $msg = json_encode([
                'msg'      => __('UsernameNotExist'),
                'username' => $param['username'] ?: "",
                'password' => $param['password']
            ], JSON_UNESCAPED_UNICODE);
            //写入登录日志
            $this->addLoginLog(0, $param['username'], 0, $msg);
            $this->error(__('%s Incorrect', [__('UsernameOrPassword')]));
        }

        //判断登录错误次数，禁止N秒内继续登录：
        $lock_count = get_config('lock_count');
        $lock_time  = get_config('lock_time');
        $logintime  = $adminInfo['logintime'];
        $left_time  = $lock_time - (time() - $logintime);
        if ( ! empty($lock_count) && $adminInfo['login_failure'] >= $lock_count && $left_time > 0) {
            $errorMsg = sprintf(lang('PasswordErrorLock'), $lock_count, $left_time);
            $this->error($errorMsg);
        }

        //加密密码
        $password = cmf_password($param['password'], $adminInfo['salt']);
        if ($password != $adminInfo['password']) {
            //拼接日志data
            $msg = json_encode([
                'msg'      => __('%s Incorrect', [__('Password')]),
                'username' => $adminInfo['username'],
                'password' => $param['password']
            ], JSON_UNESCAPED_UNICODE);
            //写入失败次数
            AdminModel::editLoginFailure($adminInfo['id'], 1);
            //写入登陆日志
            $this->addLoginLog($adminInfo['id'], $adminInfo['username'], 0, $msg);
            $this->error(__('%s Incorrect', [__('UsernameOrPassword')]));
        }
        //判断该用户是否被禁用
        if ($adminInfo['status'] != 'normal') {
            //拼接日志data
            $msg = json_encode([
                'msg'      => __('AccountDisabled'),
                'username' => $adminInfo['username'],
                'password' => "******"
            ], JSON_UNESCAPED_UNICODE);
            //写入登陆日志
            $this->addLoginLog($adminInfo['id'], $adminInfo['username'], 0, $msg);
            $this->error(__('AccountDisabled'));
        }
        //获取客户端IP地址
        $adminInfo->loginip = get_client_ip();
        //获取登录时间
        $adminInfo->logintime = time();
        $adminInfo->login_num = Db::raw('login_num+1');
        //写入数据库
        $adminInfo->save();
        //转换数据格式
        $adminInfo = $adminInfo->toArray();
        //保持登录状态  前端貌似注释了  后期可优化  todo
        $adminInfo['expire_time'] = ( ! empty($param['keep_login']) && $param['keep_login'] == 'on') ? true : time() + 3600 * 2;
        //清除密码防止泄露
        unset($adminInfo['password']);
        //拼接日志data
        $msg = json_encode([
            'msg'      => __('Login').__('Success'),
            'username' => $adminInfo['username'],
            'password' => "******"
        ], JSON_UNESCAPED_UNICODE);
        //更新登录错误次数为0
        AdminModel::editLoginFailure($adminInfo['id']);
        //写入登录日志
        $this->addLoginLog($adminInfo['id'], $adminInfo['username'], 1, $msg);
        //清除历史缓存
        Cache::clear();
        //写入登录session
        session('admin', $adminInfo);
        $this->success(__('Login').__('Success'));
    }

    /**
     * 获取后台登录验证码
     * @return \support\Response|\think\Response
     */
    public function captcha()
    {
        return Captcha::create();
    }

    /**
     * 退出登录
     * @return void
     */
    public function logout()
    {
        //清空admin的session数据
        session('admin', null);
        //清空历史缓存
        Cache::clear();
        $this->success(lang('SignOut').lang('Success'));
    }

    /**
     * 写入登录日志
     *
     * @param $adminId      日志操作者id
     * @param $adminName    日志操作者用户名
     * @param $status       状态：1=成功；0=失败
     * @param $desc         日志描述
     *
     * @return void
     */
    private function addLoginLog($adminId, $adminName, $status, $desc = '')
    {
        //后台登录日志开关
        $login_log_admin = get_config('login_log_admin');
        if ( ! $login_log_admin) {
            return;
        }
        //获取用户的相关信息的，包括用户使用的浏览器，操作系统等信息
        $Agent = $_SERVER['HTTP_USER_AGENT'];
        //获取客户端IP地址
        $getIp = get_client_ip();
        $param = [
            'user_id'     => $adminId,
            'user_name'   => $adminName,
            'browser'     => get_client_browser($Agent)['browser'] ?? "",
            'browser_ver' => get_client_browser($Agent)['browser_ver'] ?? "",
            'os'          => get_client_os($Agent)['os'] ?? "",
            'os_ver'      => get_client_os($Agent)['os_ver'] ?? "",
            'ip_address'  => $getIp,
            'status'      => $status,
            'desc'        => $desc
        ];
        //写入后台登录日志
        LoginLogModel::createLoginLog($param);
    }

}
